package com.xiannimei.service.oauth;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import net.sf.json.JSONObject;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.xiannimei.BusinessException;
import com.xiannimei.model.MemberInfo;
import com.xiannimei.service.MemberService;
import com.xiannimei.util.AvatarUtil;

public abstract class OAuthManagerAbstractImpl implements OAuthManager {

	@Autowired
	MemberService memberService;

	final Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	public OAuthProfile login(String code) {
		return localize(code);
	}

	OAuthProfile login(String token, String uid, int remain) {
		JSONObject thirdPartyUser = getThirdPartyUser(token, uid);
		return new OAuthProfile(uid, token, getNick(thirdPartyUser), remain, getPlatformId());
	}

	/**
	 * 从第三方用户信息中初始化可读的本地信息
	 * 
	 * @param userJo 第三方用户对象
	 * @return 本地话Member对象
	 * @throws IOException
	 */
	abstract String getNick(JSONObject userJo);

	/**
	 * @return 第三方平台编码
	 */
	abstract public Integer getPlatformId();

	/**
	 * @param code 第三方授权code
	 * @return 本地化用户信息
	 * @throws IOException
	 */
	abstract OAuthProfile localize(String code);

	/**
	 * @param token 授权
	 * @param uid 用户第三方ID
	 * @return 第三方用户信息
	 */
	abstract JSONObject getThirdPartyUser(String token, String uid);

	/**
	 * 第三方头像本地化
	 */
	void localizeAvatarFromRemote(MemberInfo memberInfo) {
		if (memberInfo.getMyAvatar() != null)
			AvatarUtil.createLocalAvatarFromRemote((String) memberInfo.getMyAvatar(), memberInfo.getId());
	}

	/**
	 * 构建GET请求连接URL
	 */
	String genericUrl(String... vals) {
		String url = vals[0] + "?";
		for (int i = 1; i + 1 < vals.length; i += 2)
			if (vals[i + 1] != null) {
				if (vals[i + 1].contains("://"))
					try {
						vals[i + 1] = URLEncoder.encode(vals[i + 1], "utf-8");
					} catch (UnsupportedEncodingException e) {
						log.warn("urlencode error :" + vals[i + 1], e);
						throw new BusinessException(E_GENERICURL);
					}
				url += vals[i] + "=" + vals[i + 1] + "&";
			}
		return url.substring(0, url.length() - 1);
	}

	/**
	 * 执行HTTP GET请求。
	 */
	String doGet(String url) {
		String result = "";
		HttpClient httpClient = new HttpClientIgnorCerts();
		try {
			HttpResponse resp = httpClient.execute(new HttpGet(url));
			result = EntityUtils.toString(resp.getEntity());
			EntityUtils.consume(resp.getEntity());
		} catch (Exception e) {
			log.warn("http get error :\n", e);
			log.warn("error url :\n" + url);
			httpClient = new HttpClientIgnorCerts();
			throw new BusinessException(E_HTTPGET);
		}
		return result;
	}

	JSONObject postForJson(String... vals) {
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		for (int i = 0; i < (vals.length - 1) / 2; i++)
			nvps.add(new BasicNameValuePair(vals[2 * i + 1], vals[2 * i + 2]));
		return doPost(vals[0], nvps);
	}

	/**
	 * 执行HTTP POST请求。
	 */
	private JSONObject doPost(String url, List<NameValuePair> httpParams) {
		JSONObject result = new JSONObject();
		HttpClient httpClient = new HttpClientIgnorCerts();
		try {
			HttpPost httpPost = new HttpPost(url);
			httpPost.setEntity(new UrlEncodedFormEntity(httpParams, HTTP.UTF_8));
			HttpResponse resp = httpClient.execute(httpPost);
			result = JSONObject.fromObject(EntityUtils.toString(resp.getEntity()));
			EntityUtils.consume(httpPost.getEntity());
		} catch (Exception e) {
			log.warn("http post error :\n", e);
			log.warn("error url :[{}][{}]", url, httpParams);
			httpClient = new HttpClientIgnorCerts();
			throw new BusinessException(E_HTTPPOST);
		}
		return result;
	}
}